module("framework.core.userdata.UserDataDispose", package.seeall)

--[[
    此基类是为了更好的释放对Unity/C#对象的引用而设计
    所有继承此类的子类，初始化时都要执行 __onInit 方法，销毁时要执行 __onDispose
    另外，子类要用table存放获取的Unity/C#对象时，不能直接创建table，而是要使用 getUserDataTb_ 方法获取
]]
---@class UserDataDispose : MiddleClass
local UserDataDispose = class("UserDataDispose")

-- 初始化收集userdata引用
function UserDataDispose:__onInit()
    local metaTable = getmetatable(self)
    metaTable.__newindex = function(selfObj, key, value)
        rawset(selfObj, key, value)
        if type(value) == "userdata" then
            if not rawget(selfObj, "__userDataKeys") then
                rawset(selfObj, "__userDataKeys", {})
            end
            selfObj.__userDataKeys[key] = true
            --logWarn("add userdata: " .. key .. " cname = " .. selfObj.__cname .. " obj = " .. tostring(selfObj))
        end
    end
    self.__userDataTbs = {}
    self.__eventTbs = {}
    self.__clickObjs = {}
end

-- 生命周期结束时，清除userdata引用
function UserDataDispose:__onDispose()
    if self.__userDataKeys then
        local userDataKeys = self.__userDataKeys
        for key, _ in pairs(userDataKeys) do
            rawset(self, key, nil)
            --logWarn("remove userdata: " .. key .. " cname = " .. self.__cname .. " obj = " .. tostring(self))
        end
        self.__userDataKeys = nil
    end
    -- 清除存放Unity/C#对象的table
    if self.__userDataTbs then
        for idx, tb in ipairs(self.__userDataTbs) do
            for key in pairs(tb) do
                rawset(tb, key, nil)
            end
            rawset(self.__userDataTbs, idx, nil)
        end
        self.__userDataTbs = nil
    end
    -- 清空事件监听
    if self.__eventTbs then
        for _, evtInfo in ipairs(self.__eventTbs) do
            evtInfo[1]:unregisterCallback(evtInfo[2], evtInfo[3], evtInfo[4])
            --logWarn("清空事件监听 ", tostring(evtInfo[1]), tostring(evtInfo[2]), tostring(evtInfo[3]), tostring(evtInfo[4]))
        end
        self.__eventTbs = nil
    end
    --清空点击事件
    if self.__clickObjs then
        for clickObj, _ in pairs(self.__clickObjs) do
            if not clickObj:Equals(nil) then
                clickObj:RemoveClickListener()
                --logWarn("清空事件监听 clickObj", clickObj.name)
            end
        end
        self.__clickObjs = nil
    end
end

-- 获取存放控件等Unity对象的table
function UserDataDispose:getUserDataTb_()
    local ret = {}
    if self.__userDataTbs then
        table.insert(self.__userDataTbs, ret)
    end
    return ret
end

-- 添加事件监听
function UserDataDispose:addEventCb(ctrlInstance, evtName, callback, cbObj, priority)
    if not ctrlInstance or not evtName or not callback then
        logError("UserDataDispose:addEventCb ctrlInstance or evtName or callback is null!")
        return
    end
    ctrlInstance:registerCallback(evtName, callback, cbObj, priority)
    --不重复添加
    if self.__eventTbs then
        for _, evtInfo in ipairs(self.__eventTbs) do
            if evtInfo[1] == ctrlInstance and evtInfo[2] == evtName and evtInfo[3] == callback and evtInfo[4] == cbObj then
                return
            end
        end
    end
    --logWarn("添加事件监听 ctrlInstance = ", tostring(ctrlInstance), " evtName = ", evtName, " callback = ", tostring(callback), " cbObj = ", tostring(cbObj))
    table.insert(self.__eventTbs, {ctrlInstance, evtName, callback, cbObj})
end

-- 删除事件监听
function UserDataDispose:removeEventCb(ctrlInstance, evtName, callback, cbObj)
    if not ctrlInstance or not evtName or not callback then
        logError("UserDataDispose:removeEventCb ctrlInstance or evtName or callback is null!")
        return
    end
    --移除
    if self.__eventTbs then
        for i, evtInfo in ipairs(self.__eventTbs) do
            if evtInfo[1] == ctrlInstance and evtInfo[2] == evtName and evtInfo[3] == callback and evtInfo[4] == cbObj then
                table.remove(self.__eventTbs, i)
                break
            end
        end
    end
    --logWarn("删除事件监听 ctrlInstance = ", tostring(ctrlInstance), " evtName = ", tostring(evtName), " callback = ", tostring(callback), " cbObj = ", tostring(cbObj))
    ctrlInstance:unregisterCallback(evtName, callback, cbObj)
end

-- 添加点击事件监听 ButtonWrap/UIClickListener
function UserDataDispose:addClickCb(clickObj, callback, cbObj, param)
    if not clickObj or clickObj:Equals(nil) or not callback or not cbObj then
        logError("UserDataDispose:addClickCb clickObj or callback or cbObj is null!")
        return
    end
    if self.__clickObjs and not self.__clickObjs[clickObj] then
        self.__clickObjs[clickObj] = true
        clickObj:AddClickListener(callback, cbObj, param)
        --logWarn("添加点击事件监听 clickObj = ", clickObj.name, " callback = ", tostring(callback), " cbObj = ", tostring(cbObj))
    end
end

-- 移除点击事件监听
function UserDataDispose:removeClickCb(clickObj)
    if not clickObj or clickObj:Equals(nil) then
        logError("UserDataDispose:removeClickCb clickObj is null!")
        return
    end
    if self.__clickObjs and self.__clickObjs[clickObj] then
        self.__clickObjs[clickObj] = nil
        clickObj:RemoveClickListener()
        --logWarn("移除点击事件监听 clickObj = ", clickObj.name, " callback = ", tostring(callback), " cbObj = ", (cbObj))
    end
end

return UserDataDispose
